<?php
class process {
	public $pid = -1;
	public $user_id;
	public $cmd = '';
	public $cmd_full = '';
	public $state = 0;
	public $file_out;
	public $file_err;
	public $time_start;
	public $time_end;
	public $time_run = 0;
	public $group;
	public $owner_class;
	public $owner_function;
	public $result = '';
	public $tag;
}
class processes extends wapi_mod_base {
	public $cnt = 0;
	function _construct(){
		if ($this->firstrun){
			$this->db_create();
		}
	}
	function db_create(){
		global $wapi;
		$sql = "CREATE TABLE pid (
		id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
		pid INTEGER NOT NULL,
		user_id TEXT NOT NULL,
		owner_class TEXT NOT NULL,
		owner_function TEXT NOT NULL,
		cmd TEXT NOT NULL,
		cmd_full TEXT NOT NULL,
		state INTEGER NOT NULL,
		file_out TEXT NOT NULL,
		file_err TEXT NOT NULL,
		time_start TEXT NOT NULL,
		time_end TEXT,
		time_run INTEGER,
		result TEXT,
		tag TEXT
		)";
		$wapi->db->exec($sql);
	}
	function run($cmd, $wait = -1, $tag ='',$no_log=false) {
		global $wapi;
		$backtrace = debug_backtrace();
   		$p = new process();
   		$waited = 0;
   		$p->cmd = $cmd;
   		$p->user_id = $wapi->user->user_id;
   		$p->file_out = $this->get_tmpfile();
   		$p->file_err = $this->get_tmpfile();
//		//$p->cmd_full = $cmd.' > '.$p->file_out.' 2> '.$p->file_err.' < /dev/null & echo $!';
//		if ($delay > 0) {
//			$p->cmd_full = 'nohup sh -c "sleep '.$delay.' && '.$cmd.' 1> '.$p->file_out.' 2> '.$p->file_err.' < /dev/null" & echo $!';
//		} else {
			$p->cmd_full = 'nohup sh -c "'.$cmd.' 1> '.$p->file_out.' 2> '.$p->file_err.' < /dev/null" & echo $!';
//		}
		$p->cmd_full = "nohup $cmd 1> $p->file_out 2> $p->file_err < /dev/null & echo " . '$!';
		$p->time_start = date("Y-m-d H:i:s",time());
		$p->state = 1;
		$p->owner_class = $backtrace[1]['class'];
		$p->owner_function = $backtrace[1]['function'];
		$p->tag = $tag;
		$p->pid = shell_exec($p->cmd_full);
		if ($p->pid > 0 && !$no_log) {
			// Save to pid table
			$sql = "INSERT INTO pid (pid,user_id,cmd,cmd_full,state,file_out,file_err,time_start,owner_class,owner_function,tag)
			VALUES ($p->pid,'" . $p->user_id . "','" . $wapi->db->esc($cmd) . "','" . $wapi->db->esc($p->cmd_full) . "',
			$p->state,'" . $wapi->db->esc($p->file_out) . "','" . $wapi->db->esc($p->file_err) . "',
			'" . $wapi->db->esc($p->time_start) . "','" . $wapi->db->esc($p->owner_class) . "',
			'" . $wapi->db->esc($p->owner_function) . "','" . $wapi->db->esc($p->tag) . "')";
			$ret = $wapi->db->exec($sql);
			// - Save to pid table
			if ($wait >= 0) {
				while($this->pid_running($p->pid)) {
					sleep(1);
					$n = date("Y-m-d H:i:s",time());
					$waited = $this->time_diff($p->time_start,$n);
					if ($wait > 0 && $waited >= $wait) {
						break;
					}
				}
				$this->poll();
			}
		}
		return $p;
	}
	function poll(){
		// Load all runnning processes from db
		global $wapi;
		$cnt = 0;
		$sql = 'SELECT * FROM pid WHERE state = 1';
		// - Load all runnning processes from db
		if ($wapi->db->query($sql)){
			$res = $wapi->db->results;
			foreach ($res as $r) {
				$running = $this->pid_running($r['pid']);
				$result = '';
				$time_end = '';
				$time_run = '';
				$running = false;
				$state = 0;
				$done_time = '';
				if (!$running) {
					// read and delete the output files
					if (is_file($r['file_out'])){
						if (filesize($r['file_out']) != 0) {
							$done_time = filemtime($r['file_out']);
							$result = file_get_contents($r['file_out']);
							$state = 0;
						}
						unlink($r['file_out']);
					}
					if (is_file($r['file_err'])){
						if (filesize($r['file_err']) != 0) {
							$done_time = filemtime($r['file_err']);
							$result = file_get_contents($r['file_err']);
							$state = -1;
						}
						unlink($r['file_err']);
					}
					if ($done_time == ''){
						$time_end = $r['time_start'];
					} else {
						$time_end = date("Y-m-d H:i:s",$done_time);
					}
					$time_run = $this->time_diff($r['time_start'],$time_end);
					// Save to pid table
					$sql = "UPDATE pid SET
					state = $state,
					result = '" . $wapi->db->esc($result) . "',
					time_end = '" . $wapi->db->esc($time_end) . "',
					time_run = $time_run
					WHERE
					pid = " . $r['pid'] . " AND state = 1";
					$ret = $wapi->db->exec($sql);
					// -Save to pid table
				} else {
					// read any output so far and save to db
					$cnt ++;
				}
			}
		}
		$this->cnt = $cnt;
		return $cnt;
	}
	function pid_running($pid){
		exec("ps $pid", $pstate);
		return(count($pstate) >= 2);
   	}
	function get_tmpfile(){
		$fname = tempnam(sys_get_temp_dir(), 'wapi');
		return $fname;
	}
	function time_diff($firstTime,$lastTime){
		$firstTime = strtotime($firstTime);
		$lastTime = strtotime($lastTime);
		$timeDiff = $lastTime - $firstTime;
		return $timeDiff;
	}
	function show_processes($show_all = false, $clear_done = false){
		echo "Process count: " . $this->run_cnt . " (" . count($this->proc) . ")<br />\n";
		if (count($this->proc) > 0) {
			foreach ($this->proc as $i => $p){
				if ($p->state == 1 || $show_all) {
					$this->show_pid($i);
				}
			}
		}
		if ($clear_done) {
			$this->clear_done();
		}
	}
	function show_pid($i){
		$p = $this->proc[$i];
		echo "Index: " . $i . "<br />\n";
		echo "PID: " . $p->pid . "<br />\n";
		echo "Cmd: " . $p->cmd . "<br />\n";
		echo "Full Cmd: " . $p->full_cmd . "<br />\n";
		echo "State: " . $p->state . "<br />\n";
		echo "Data Cnt: " . strlen($p->result) . "<br />\n";
		echo "Err Cnt: " . strlen($p->err) . "<br />\n";
		echo "Start: " . $p->time_start . "<br />\n";
		echo "End: " . $p->time_end . "<br />\n";
		echo "Runtime: " . $p->runtime . "<br />\n";
		echo "<br />";
	}
	function get_pid($job_name,$field){
		global $wapi;
		$sql = "SELECT $field FROM cron_jobs WHERE job_name = '$job_name'";
		if ($wapi->db->query($sql)) {
			$res = $wapi->db->results;
			$r = $res[0];
			return $r[$field];
		}
		return null;
	}
	function set_job($job_name,$field,$value){
		global $wapi;
		if (is_string($value)){
			$sql = "UPDATE cron_jobs SET $field = '$value' WHERE job_name = '$job_name'";
		} else {
			$sql = "UPDATE cron_jobs SET $field = $value WHERE job_name = '$job_name'";
		}
		$ret = $wapi->db->exec($sql);
	}
}
?>